package com.chengjj.kings.core.filter;

import com.chengjj.kings.config.properties.EncryptProperties;
import com.chengjj.kings.core.base.warpper.EncryptionRequestWrapper;
import com.chengjj.kings.core.base.warpper.EncryptionResponseWrapper;
import com.chengjj.kings.core.util.AESTool;
import com.chengjj.kings.core.util.ToolUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: 成俊杰
 * @CreateDate: 2019/3/18
 * @Version: 1.0
 * @Description: 加解密filter 避免被抓包
 */
@Slf4j
@Component
public class EncryptionFilter extends OncePerRequestFilter {
    private static final String DEFAULT_ENCRYPT_KEY = "Ytf7^bwfMgnbnapo";

    @Autowired
    private EncryptProperties encryptProperties;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String platform = request.getParameter("p");
        String data = request.getParameter("d");

        if (!encryptProperties.getEnabled()) {
            super.doFilter(request, response, filterChain);
        }

        if (ToolUtil.isNotEmpty(platform) && ToolUtil.isNotEmpty(data)) {
            try {
                Map<String, String> qMap = parseEncryptionParams(AESTool.decryptString(URLDecoder.decode(data, request.getCharacterEncoding()).replace(" ", "+"), getSecretKey(platform)));
                if (qMap != null && ToolUtil.isNotEmpty(qMap.get("sk"))) {
                    Map<String, String[]> parameterMap = new HashMap<>(request.getParameterMap());
                    for (Map.Entry<String, String> e : qMap.entrySet()) {
                        try {
                            parameterMap.put(e.getKey(), new String[]{URLDecoder.decode(e.getValue(), request.getCharacterEncoding())});
                        } catch (Exception ex) {
                            parameterMap.put(e.getKey(), new String[]{e.getValue()});
                        }
                    }
                    EncryptionRequestWrapper encryptionRequestWrapper = new EncryptionRequestWrapper(request, parameterMap);
                    EncryptionResponseWrapper encryptionResponseWrapper = new EncryptionResponseWrapper(response);
                    encryptionRequestWrapper.setAttribute("encrypt", true);
                    super.doFilter(encryptionRequestWrapper, encryptionResponseWrapper, filterChain);
                    byte[] responseData = encryptionResponseWrapper.getResponseData();
                    log.debug("原始返回数据： " + new String(responseData, request.getCharacterEncoding()));
                    String responseBodyMw = AESTool.encryptString(new String(responseData, request.getCharacterEncoding()), qMap.get("sk"));
                    log.debug("加密返回数据： " + responseBodyMw);
                    response.setContentType(String.format("text/plain;charset=%s", request.getCharacterEncoding()));
                    writeResponse(response, responseBodyMw);
                } else {
                    super.doFilter(request, response, filterChain);
                }
            } catch (Exception e) {
                super.doFilter(request, response, filterChain);
            }
        } else {
            super.doFilter(request, response, filterChain);
        }
    }

    private void writeResponse(ServletResponse response, String responseString)
            throws IOException {
        PrintWriter out = response.getWriter();
        out.print(responseString);
        out.flush();
        out.close();
    }


    private String getRequestBody(HttpServletRequest request) {
        try {
            return IOUtils.toString(request.getReader());
        } catch (IOException e) {
            log.error("read request error", e);
        }
        return null;
    }

    private Map<String, String> parseEncryptionParams(String content) {
        if (ToolUtil.isEmpty(content)) {
            return null;
        }
        String[] arr = content.split("&");
        Map<String, String> map = new HashMap<>();
        for (String params : arr) {
            if (ToolUtil.isNotEmpty(params)) {
                if (params.contains("=")) {
                    String key = params.substring(0, params.indexOf("="));
                    String value = params.substring(key.length() + 1);
                    map.put(key, value);
                } else {
                    map.put(params, "");
                }
            }
        }
        return map;
    }


    private String getSecretKey(String f) {
        if (encryptProperties == null || encryptProperties.getEncryptions() == null ||
                ToolUtil.isEmpty(encryptProperties.getEncryptions().get(f))) {
            return DEFAULT_ENCRYPT_KEY;
        }

        return encryptProperties.getEncryptions().get(f);
    }
}
